package cn.hesion.dataStructures.sortingorder;

import cn.hesion.array.Array;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Arrays;

/**
 * 也是插入排序的一种
 */
public class ShellSort {
    public static void main(String[] args) {
//        int[] arr = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0};
//        shellSortSwap(arr);
        //        int[] arr = {101, 34, 119, 1};
        int[] arr = new int[8000000];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) (Math.random() * 8000000);
        }
//        System.out.println("排序前");
//        System.out.println(Arrays.toString(arr));
        Long before = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        System.out.println("排序前系统时间毫秒:" + before);
//        shellSortSwap(arr);
        shellSortMove(arr);
        Long after = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        System.out.println("排序前系统时间毫秒:" + after);
        System.out.println("本次希尔排序共耗时:" + (after - before) + "ms");
//        int[] arr1 = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0};
//        shellSortMove(arr1);
//        System.out.println(Arrays.toString(arr1));

    }

    public static void shellSortTD(int[] arr) {
        //希尔排序的第1轮
        //第1轮排序，是将10个数据分成10/2=5组,每组2个 步长5
        for (int i = 5; i < arr.length; i++) {
            for (int j = i - 5; j >= 0; j -= 5) {
                if (arr[j] > arr[j + 5]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 5];
                    arr[j + 5] = temp;
                }
            }
        }
        System.out.println("希尔排序1轮后=" + Arrays.toString(arr));

        //希尔排序的第2轮
        //第2轮排序，是将10个数据分成5/2组,每组5个，步长2
        for (int i = 2; i < arr.length; i++) {
            for (int j = i - 2; j >= 0; j -= 2) {
                if (arr[j] > arr[j + 2]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 2];
                    arr[j + 2] = temp;
                }
            }
        }
        System.out.println("希尔排序2轮后=" + Arrays.toString(arr));
        //希尔排序的第3轮
        //第3轮排序，是将10个数据分成2/2=1组个,步长1
        for (int i = 1; i < arr.length; i++) {
            for (int j = i - 1; j >= 0; j -= 1) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
        System.out.println("希尔排序3轮后=" + Arrays.toString(arr));
    }

    //交换法Shell
    public static void shellSortSwap(int[] arr) {
        //希尔排序的第n轮
        //第n轮排序，是将m个数据分成m/2组,每组m/gap个 步长gap
        int gap = 0;
        int count = 0;
//        System.out.println("未排序前的arr情况:"+Arrays.toString(arr));
        //这层循环控制分组
        for (gap = arr.length / 2; gap > 0; gap /= 2) {
            //这一层用于遍历各个分组
            for (int i = gap; i < arr.length; i++) {
                //这一层用于分组内的遍历
                for (int j = i - gap; j >= 0; j -= gap) {
                    if (arr[j] > arr[j + gap]) { // a:arr[j] b: arr[j+gap]
                     int temp = arr[j+gap];
                     arr[j+gap]=arr[j];
                     arr[j]=temp;
//                        arr[j] = arr[j] ^ arr[j + gap];
//                        arr[j + gap] = arr[j] ^ arr[j + gap];
//                        arr[j] = arr[j] ^ arr[j + gap];
                    }
                }
            }
//            System.out.println("第"+(count+1)+"轮希尔排序,gap="+gap);
//            count++;
//            System.out.println("此时的arr情况:"+Arrays.toString(arr));
        }

    }

    //移位法
    public static void shellSortMove(int[] arr) {
        int gap = 0;
        int count = 0;
//        System.out.println("未排序前的arr情况:"+Arrays.toString(arr));
        //这层循环控制分组
        for (gap = arr.length / 2; gap > 0; gap /= 2) {
            //这一层用于遍历各个分组
            for (int i = gap; i < arr.length; i++) {
                //移位法，在组内进行插入排序
                int insertIndex = i;
                int insertNum = arr[insertIndex];
                if (arr[insertIndex] < arr[insertIndex - gap]) {
                    //一个分组内，前面的元素比后面元素大则开始移位
                    while (insertIndex - gap >= 0 && insertNum < arr[insertIndex - gap]) {
                        // 覆盖操作，直接后面的数覆盖前面的数
                        arr[insertIndex] = arr[insertIndex-gap];
                        insertIndex -= gap;
                    }
                    //循环结束 将刚才存的值，覆盖上去
                    arr[insertIndex]=insertNum;
                }
            }
//            System.out.println("第"+(count+1)+"轮希尔排序,gap="+gap);
//            count++;
//            System.out.println("此时的arr情况:"+Arrays.toString(arr));
        }
    }
}
